from concurrent.futures import ProcessPoolExecutor
from concurrent.futures import Future
import urllib.request as ur
import numpy as np
import re
import os

# def deal(response):
#     """
#         this is default deal function for response
#     """
#     return response.read()

class AsynTask(object):
    """docstring for AsynTask
        must implement callback, do

        do (sample):
        def do(self,url):
            try:
                response = ur.urlopen(url)        
            except Exception  as e:
                print(e)
            except Future.exception(timeout=self.timeout):
                print("time out :",self.timeout)
            finally:
                return response 

        callback (sample):
        def callback(self,future):
            result = future.result()
            if future in  HTTP.temp_future:
                arg = HTTP.temp_future[future]
            with open(arg[-1]+".log","w") as fp:
                print(result,file=fp

    """
    executor = None
    temp_future = None
    def __init__(self,max_process=7,timeout=5):

        if AsynTask.executor != None :pass
        else:
            print(" ---- init executor ----")
            self.timeout = timeout
            AsynTask.executor = ProcessPoolExecutor(max_workers=max_process)
            AsynTask.temp_future = {}
    
    def do_background(self,args,callback=None):
        """
        must give a callback for some dealing just like deal with UI.
        @args must () or []
        @callback should implement or pass .

        """
        con = None
        if isinstance(args,list):
            args.append(deal)
            con = AsynTask.executor.submit(self.do,*args)
        else:
            con = AsynTask.executor.submit(self.do,args)
        
        # must give a callback for some dealing just like deal with UI
        if callback == None:  
            con.add_done_callback(self.callback)
        else:
            con.add_done_callback(callback)

        AsynTask.temp_future[con] = args


    def get_args(self,future):
        r = AsynTask.temp_future[future]
        del AsynTask.temp_future[future]
        return r

    def clear(self):
        HTTP.executor = None


    def callback(self,future):
        """
        this is must implement
        """
        # result = future.result()
        # args = self.get_args(future)
        # print("args : ",args,"\nresult: ",result )

    def do(self):
        """
         this is must implement
        """
        pass

    
class HTTP(AsynTask):
    """
        a simple for get some thing from http
        just implement GET
    """

    data = {}
    save_or_not = False
    resource_info = None

    def do(self,url):
        try:
            response = ur.urlopen(url)
        except Exception  as e:
            print(e)
        except Future.exception(timeout=self.timeout):
            print("time out :",self.timeout)
        finally:
            return response.read().decode("utf8")

    def callback(self,future):
        result = future.result()
        args = self.get_args(future)
        

    def Get(self,url,callback):
        """
        
        """
        self.do_background(url,callback=callback)

    def set_save(self,save_or_not=True):
        HTTP.save = save_or_not
    
    def get_pages(self):
        if HTTP.resource_info:
            print("resource_info :",HTTP.resource_info)
            pa = 0
            try:
                pa = int(HTTP.resource_info[3])
            except ValueError:
                pa = int(HTTP.resource_info[4])
            return pa

def print_data(data,save_file=False):
    ma = re.compile(r'(\d{2,4}-){2}(\d{1,2})')
    fp = None
    for i in range(len(data)):
        if ( re.match( ma, data[i]) != None):
            
            if save_file :
                if fp == None:
                    print(" - - save mode - - ")
                fp = open(os.path.join("city",data[i-1]),"a+")
                    # print(" - - open file - - ")
                try:
                    int(data[i+1])

                    one_item = ",".join([data[i],data[i+1]])
                except ValueError :
                    print (data[i+1])
                    one_item = ",".join([data[i],'0'])                
                except IndexError:
                    print('err : i = ',i,len(data),data)
                    one_item = None
                finally:
                    if one_item:
                        print(one_item,file=fp)
                    fp.close()
            else:
                print("| %14s | %14s | %14s |\n"%(data[i-1],data[i],data[i+1]))    
    if fp :
        fp.close()

def para_report(future):
    # s = re.compile(r '<td\s(colspan.+?class="report1_15">(.+?)</td>')
    text = future.result()
    arg = AsynTask.temp_future[future]
    save = HTTP.save

    s = re.compile(r'<.+?>')
    # return re.findall(s,text)
    temp =  re.split(s, text)
    print (arg[-2:])
    all_info = [ i.strip() for i in temp if i.strip() != '' and len(i) <30 ]
    data_info = all_info[6:-15]
    resource_info = all_info[-15:]
    # print(all_info[:6])
    print_data(data_info,save)
    # print(resource_info)


def get_report_info(future):
    text = future.result()
    save = HTTP.save


    s = re.compile(r'<.+?>')
    # return re.findall(s,text)
    temp =  re.split(s, text)
    # print (temp)
    all_info = [ i.strip() for i in temp if i.strip() != '' and len(i) <30 ]

    resource_info = all_info[-15:-9]
    print(resource_info)
    HTTP.resource_info = resource_info



def scaledown(raw_data,rate=0.01,times=200):
    """
        generate point in 2D
    """
    from math import sqrt
    
    INDEX =  raw_data.index
    COLUMNS = raw_data.columns
    print(" --- calculate pearson --- ")
    data = (1-raw_data.corr()).values
    print(" ---         ok        ---")

    n = len(COLUMNS)
    display_compare = []
    #real distance between  every pair of items
    realdist =  data


    outersum = 0.0

    #Randomly  initialize the starting points of the loacations in 2D
    # loc = [[random.random(),random.random()] for i in range(n)]
    loc = np.abs(np.random.randn(n,2))
    fakedist = [[0.0 for  j in range(n)] for i in range(n)]
    loc_column = 2

    lasteerror =  None
    for m in range(0,times):
        NO = m
        #Find projected distances
        for i in range(n):
            for j in range(n):
                fakedist[i][j] = sqrt (sum([pow (loc[i][x] -loc[j][x],2 )
                                        for x in range(loc_column)]))
        #MMoved points
        grad = [[0.0, 0.0 ] for i in range(n) ]

        totalerror = 0
        for k in range(n):
            if  j ==k :
                continue 

            # Thee error is percent difference  between the distances 
            if realdist[j][k] == 0:
                continue
            errorterm = (fakedist[j][k] - realdist[j][k] )/realdist[j][k]
            # print("error : {} ".format(errorterm),end="\r")

            #Each point nedds to be moved away from or toards the other 
            # point in propety to how much error  it has 
            grad[k][0] += ((loc [k][0] - loc [j][0] )/ fakedist[j][k])* errorterm
            grad[k][1] += ((loc [k][1] - loc[j][1] ) / fakedist[j][k] ) * errorterm

            #Keep track of the total error 
            totalerror = abs(errorterm)
        print ('[{}\/{}] total error : {} => target : {}'.format(NO,100,totalerror,rate),end='\r')
        
        #if the answer got worse by moving the points , we are done 
        if lasteerror and lasteerror <  totalerror : break
        lasteerror = totalerror

        #move each of  the points by the learning  rate times the gradient 
        for k in range(n):
            loc[k][0] -= rate  * grad[k][0]
            loc[k][1] -= rate * grad[k][1]
    return loc

def static_relation(data,times=200):
    print(" --- calculate location ----- ")
    data_loc = pd.DataFrame(scaledown(data,times=times),index=data.columns)
    acculate = data.sum()
    max_v = acculate.max()
    point_size = acculate / max_v
    data_loc.join(pd.DataFrame(point_size))
    return data_loc

# def city_real_distance():



# if __name__ == "__main__":
#     client = HTTP()
#     uri = [ "http://datacenter.mep.gov.cn/report/air_daily/air_dairy.jsp?city=&startdate=2015-12-2&enddate=2015-12-24&page="+str(i) for i in range(10)]
#     for l in uri :
#         res = client.Get(l,client.callback)
#         print(res)
# class  Data(object):
#     """docstring for  Data"""
#     def __init__(self, ):
#         super( Data, self).__init__()
#         self.arg = arg
        